package org.aeon.client.view.components.sessionPanel;

import org.aeon.client.context.GlobalContext;
import org.aeon.constant.BiasDirection;
import org.aeon.constant.MessageSendStatus;
import org.aeon.entity.ChatMessage;
import org.aeon.entity.User;
import org.aeon.entity.dto.GroupInfoDto;
import org.aeon.entity.dto.UserDto;
import org.aeon.entity.dto.UserInfoDto;
import org.aeon.utils.ImageSetUtil;
import org.aeon.utils.SwingUtil;

import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.io.Serial;
import java.text.SimpleDateFormat;
import java.util.Date;

import static org.aeon.constant.MessageSendStatus.NORMAL;

/**
 * @author: MissingAeon
 * @date: 2024/2/26 12:42
 * @description:
 */
public class ChatRecordItem extends JPanel {
    private final JLabel nicknameLabel;
    private final JLabel timeLabel;
    private final JTextPane textPane;
    private final JPanel panel;
    private JLabel promptLabel;
    private BiasDirection direction;

    public ChatRecordItem(BiasDirection direction, MessageSendStatus sendStatus) {
        this.direction = direction;
        // this.setBackground(Color.GREEN);
        this.setOpaque(false);
        // this.
        this.setLayout(new GridBagLayout());

        // 昵称
        nicknameLabel = new JLabel("昵称");
        nicknameLabel.setFont(new Font("黑体", Font.PLAIN, 22));

        timeLabel = new JLabel("时间");

        final Box nicknameBox = Box.createHorizontalBox();

        this.panel = SwingUtil.roundedPanel();

        this.panel.setLayout(new BoxLayout(this.panel, BoxLayout.Y_AXIS));
        // panel.setOpaque(false);
        this.panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        // panel.setBackground(Color.WHITE);


        // 消息内容
        textPane = new JTextPane();
        textPane.setEditorKit(new WrapEditorKit());
        textPane.setSize(new Dimension(350, Short.MAX_VALUE));
        textPane.setFont(new Font("黑体", Font.PLAIN, 16));
        // 设置为不可编辑
        textPane.setEditable(false);
        // 设置边框
        textPane.setBorder(null);

        textPane.setBackground(Color.WHITE);


        StyledDocument style = textPane.getStyledDocument();
        SimpleAttributeSet align = new SimpleAttributeSet();
        style.setParagraphAttributes(0, style.getLength(), align, false);

        GridBagConstraints gbc = new GridBagConstraints();

        // 消息项位置
        switch (direction) {
            case LEFT -> {
                nicknameBox.add(nicknameLabel);
                nicknameBox.add(Box.createHorizontalStrut(20));
                nicknameBox.add(timeLabel);
                nicknameBox.add(Box.createHorizontalGlue());

                this.panel.add(textPane);

                gbc.gridx = 0;
                gbc.gridy = GridBagConstraints.RELATIVE;
                gbc.fill = GridBagConstraints.NONE;
                gbc.anchor = GridBagConstraints.WEST;
                this.add(nicknameBox, gbc);
                this.add(this.panel, gbc);
                gbc.gridx = 1;
            }
            case RIGHT -> {
                nicknameBox.add(Box.createHorizontalGlue());
                nicknameBox.add(timeLabel);
                nicknameBox.add(Box.createHorizontalStrut(20));
                nicknameBox.add(nicknameLabel);

                this.panel.add(textPane);

                gbc.gridx = 1;
                gbc.gridy = GridBagConstraints.RELATIVE;
                gbc.fill = GridBagConstraints.NONE;
                gbc.anchor = GridBagConstraints.EAST;
                this.add(nicknameBox, gbc);
                this.add(this.panel, gbc);
                gbc.gridx = 0;

            }
        }

        // 提示图标
        gbc.gridy = 0;
        gbc.gridheight = 2;
        gbc.fill = GridBagConstraints.VERTICAL;
        // 设置组件在单元格中的上下居中
        gbc.anchor = GridBagConstraints.CENTER;
        promptLabel = new JLabel();
        promptLabel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
        this.setStatus(sendStatus);
        this.add(promptLabel, gbc);

    }


    /**
     * 加载这条消息的具体内容信息
     *
     * @param user
     * @param chatMessage
     */
    public void load(UserInfoDto user, ChatMessage chatMessage) {
        final User currentUser = GlobalContext.getContext().getCurrentUser();
        nicknameLabel.setText(direction == BiasDirection.LEFT ? user.getNickname() : currentUser.getNickname());
        load0(chatMessage);

    }

    /**
     * 加载这条消息的具体内容信息
     *
     * @param group
     * @param message
     */
    public void load(GroupInfoDto group, ChatMessage message) {
        final User currentUser = GlobalContext.getContext().getCurrentUser();
        nicknameLabel.setText(direction == BiasDirection.LEFT ?
                group.getMembers()
                        .stream()
                        .filter(m -> m.getId() == message.getFrom())
                        .findAny()
                        .orElse(new UserDto("ID:" + message.getFrom()))
                        .getNickname()
                : currentUser.getNickname());
        load0(message);

    }

    private void load0(ChatMessage chatMessage) {
        this.timeLabel.setText(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                .format(new Date(chatMessage.getCreationTime())));
        textPane.setText(chatMessage.getContent());

        // 字段长度
        final int stringWidth = SwingUtil.getStringWidth(textPane.getText(), textPane.getFont()) + 1;
        // 宽度
        final int width = Math.min(stringWidth, 350);
        // 高度
        final int height = (SwingUtil.getStringHeight(textPane.getText(), textPane.getFont()) + 1) * ((stringWidth / 350) + 1);
        // textPane大小
        SwingUtil.setSize(textPane, new Dimension(width, height));
        // panel大小
        SwingUtil.setSize(panel, new Dimension(width + 20, height + 20));
    }

    /**
     * 修改这个消息的状态
     *
     * @param status
     */
    public void setStatus(MessageSendStatus status) {
        SwingUtilities.invokeLater(() -> {
            if (status == NORMAL) {
                promptLabel.setIcon(null);
            } else {
                promptLabel.setIcon(new ImageIcon(
                        ImageSetUtil.getImage(switch (status) {
                            case SENDING -> "loading";
                            case SEND_FAILED -> "warning";
                            default -> throw new IllegalArgumentException();
                        }, 30, 30)));
            }
        });
    }

    private static class WrapLabelView extends LabelView {
        public WrapLabelView(Element elem) {
            super(elem);
        }

        public float getMinimumSpan(int axis) {
            return switch (axis) {
                case View.X_AXIS -> 0;
                case View.Y_AXIS -> super.getMinimumSpan(axis);
                default -> throw new IllegalArgumentException("Invalid axis: " + axis);
            };
        }

    }

    private static class WrapColumnFactory implements ViewFactory {
        public View create(Element elem) {
            String kind = elem.getName();
            if (kind != null) {
                return switch (kind) {
                    case AbstractDocument.ContentElementName -> new WrapLabelView(elem);
                    case AbstractDocument.ParagraphElementName -> new ParagraphView(elem);
                    case AbstractDocument.SectionElementName -> new BoxView(elem, View.Y_AXIS);
                    case StyleConstants.ComponentElementName -> new ComponentView(elem);
                    case StyleConstants.IconElementName -> new IconView(elem);
                    default -> new LabelView(elem);
                };
            }
            // default to text display
            return new LabelView(elem);
        }
    }

    private static class WrapEditorKit extends StyledEditorKit {
        @Serial
        private static final long serialVersionUID = -8358830861712934921L;
        ViewFactory defaultFactory = new WrapColumnFactory();

        public ViewFactory getViewFactory() {
            return defaultFactory;
        }
    }
}
